size_estimation.test.js ➔ makeUtxo   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 3
c 2
b 0
f 0
nc 4
dl 0
loc 13
rs 9.4285
nop 3
1
/* jshint -W101, -W098 */
2
/* global window */
3
var assert = require('assert');
4
var bitcoin = require('bitcoinjs-lib');
5
var SizeEstimation = require("../lib/size_estimation");
6
7
function makeUtxo(script, rs, ws) {
8
    var utxo = {
9
        scriptpubkey_hex: script.toString('hex'),
10
        value: 100000000
11
    };
12
    if (rs instanceof Buffer) {
0 ignored issues
show
Bug introduced by
The variable Buffer seems to be never declared. If this is a global, consider adding a /** global: Buffer */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
13
        utxo.redeem_script = rs.toString('hex');
14
    }
15
    if (ws instanceof Buffer) {
16
        utxo.witness_script = ws.toString('hex');
17
    }
18
    return utxo;
19
}
20
21
function scriptUtxos(script) {
22
    var hash160 = bitcoin.crypto.hash160(script);
23
    var p2shSPK = bitcoin.script.scriptHash.output.encode(hash160);
24
25
    var sha256 = bitcoin.crypto.sha256(script);
26
    var p2wshSPK = bitcoin.script.witnessScriptHash.output.encode(sha256);
27
28
    var p2wshHash160 = bitcoin.crypto.hash160(p2wshSPK);
29
    var p2wshP2sh = bitcoin.script.scriptHash.output.encode(p2wshHash160);
30
31
    var bareUtxo = makeUtxo(script, null, null);
32
    var p2shUtxo = makeUtxo(p2shSPK, script, null);
33
    var p2wshUtxo = makeUtxo(p2wshSPK, null, script);
34
    var p2shP2wshUtxo = makeUtxo(p2wshP2sh, p2wshSPK, script);
35
36
    return {
37
        bareUtxo: bareUtxo,
38
        p2shUtxo: p2shUtxo,
39
        p2wshUtxo: p2wshUtxo,
40
        p2shP2wshUtxo: p2shP2wshUtxo
41
    };
42
}
43
44
function makeUtxoFixtures(script, scriptSizes, extra) {
45
    var utxos = scriptUtxos(script);
46
    var result = [
47
        [utxos.bareUtxo, scriptSizes.bareSig, 0],
48
        [utxos.p2shUtxo, scriptSizes.p2shSig, 0],
49
        [utxos.p2wshUtxo, 1, scriptSizes.nestedWit],
50
        [utxos.p2shP2wshUtxo, scriptSizes.nestedSig, scriptSizes.nestedWit]
51
    ];
52
53
    if (Array.isArray(extra) && extra.length > 0) {
54
        for (var i = 0; i < result.length; i++) {
55
            result[i] = result[i].concat(extra);
56
        }
57
    }
58
59
    return result;
60
}
61
62
function makeFormFixtures(script, scriptSizes, extra) {
63
    var result = [
64
        [script, false, null, null, scriptSizes.bareSig, 0],
65
        [script, false, script, null, scriptSizes.p2shSig, 0],
66
        [script, true, null, script, 1, scriptSizes.nestedWit],
67
        [script, true, scriptSizes.p2wshScript, script, scriptSizes.nestedSig, scriptSizes.nestedWit]
68
    ];
69
70
    if (Array.isArray(extra) && extra.length > 0) {
71
        for (var i = 0; i < result.length; i++) {
72
            result[i] = result[i].concat(extra);
73
        }
74
    }
75
76
    return result;
77
}
78
79
function p2pkScriptSizes(script) {
80
    var bareSize = (1 + SizeEstimation.SIZE_DER_SIGNATURE);
81
    var bareSig = 1 + bareSize;
82
    var p2shSig = 1 + bareSize + 1 + script.length;
83
84
    var p2wshHash = bitcoin.crypto.sha256(script);
85
    var p2wshScript = bitcoin.script.witnessScriptHash.output.encode(p2wshHash);
86
87
    var nestedSig = 1 + 1 + p2wshScript.length;
88
    var witSize = (1 + SizeEstimation.SIZE_DER_SIGNATURE);
89
    var nestedWit = witSize + 1 + 1 + script.length;
90
91
    return {
92
        bareSig: bareSig,
93
        p2shSig: p2shSig,
94
        p2wshScript: p2wshScript,
95
        nestedSig: nestedSig,
96
        nestedWit: nestedWit
97
    };
98
}
99
100
function p2pkMakeScript(wif, network) {
101
    var uncompressed = bitcoin.ECPair.fromWIF(wif, network);
102
    var keyu = uncompressed.getPublicKeyBuffer();
103
    return bitcoin.script.pubKey.output.encode(keyu);
104
}
105
106 View Code Duplication
function p2pkhScriptSizes(script, compressed) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
107
    var bareSize = (1 + SizeEstimation.SIZE_DER_SIGNATURE) + (1 + (compressed ? 33 : 65));
108
    var bareSig = 1 + bareSize;
109
    var p2shSig = 1 + bareSize + 1 + script.length;
110
111
    var p2wshHash = bitcoin.crypto.sha256(script);
112
    var p2wshScript = bitcoin.script.witnessScriptHash.output.encode(p2wshHash);
113
114
    var nestedSig = 1 + 1 + p2wshScript.length;
115
    var witSize = (1 + SizeEstimation.SIZE_DER_SIGNATURE) + (1 + (compressed ? 33 : 65));
116
    var nestedWit = witSize + 1 + 1 + script.length;
117
118
    return {
119
        bareSig: bareSig,
120
        p2shSig: p2shSig,
121
        p2wshScript: p2wshScript,
122
        nestedSig: nestedSig,
123
        nestedWit: nestedWit
124
    };
125
}
126
127
function p2pkhMakeScript(wif, network) {
128
    var eckey = bitcoin.ECPair.fromWIF(wif, network);
129
    var hash160 = bitcoin.crypto.hash160(eckey.getPublicKeyBuffer());
130
    return bitcoin.script.pubKeyHash.output.encode(hash160);
131
}
132
133
function p2pkhFormFixture(wif, network) {
134
    var keyHash = p2pkhMakeScript(wif, network);
135
    var compressed = bitcoin.ECPair.fromWIF(wif, network).compressed;
136
    var scriptSizes = p2pkhScriptSizes(keyHash, compressed);
137
    return makeFormFixtures(keyHash, scriptSizes, [compressed]);
138
}
139
140
function p2pkMakeFormFixtures(wif, network) {
141
    var script = p2pkMakeScript(wif, network);
142
    var scriptSizes = p2pkScriptSizes(script);
143
    return makeFormFixtures(script, scriptSizes);
144
}
145
function multisigMakeScript(m, wifs, network) {
146
    var keys = wifs.map(function(wif) {
147
        return bitcoin.ECPair.fromWIF(wif, network).getPublicKeyBuffer();
148
    });
149
150
    return bitcoin.script.multisig.output.encode(m, keys);
151
}
152 View Code Duplication
function multisigScriptSizes(m, script) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
153
    var bareSize = 1/*op0*/ + m * (1 + SizeEstimation.SIZE_DER_SIGNATURE);
154
    var bareSig = 1 + bareSize;
155
    var p2shSig = bareSize + SizeEstimation.getLengthForScriptPush(script.length) + script.length;
156
157
    var p2wshHash = bitcoin.crypto.sha256(script);
158
    var p2wshScript = bitcoin.script.witnessScriptHash.output.encode(p2wshHash);
159
160
    var nestedSig = 1 + 1 + p2wshScript.length;
161
    var witSize = 1 + m * (1 + SizeEstimation.SIZE_DER_SIGNATURE);
162
    var nestedWit = witSize + 1 + 1 + script.length;
163
164
    return {
165
        bareSig: bareSig,
166
        p2shSig: SizeEstimation.getLengthForVarInt(p2shSig) + p2shSig,
167
        p2wshScript: p2wshScript,
168
        nestedSig: nestedSig,
169
        nestedWit: nestedWit
170
    };
171
}
172
173
var varIntFixtures = [
174
    [0, 1],
175
    [1, 1],
176
    [252, 1],
177
    [253, 3],
178
    [254, 3],
179
    [65534, 3],
180
    [65535, 5],
181
    [65536, 5],
182
    [Math.pow(2, 31), 5],
183
    [Math.pow(2, 32) - 2, 5],
184
    [Math.pow(2, 32) - 1, 9],
185
    [Math.pow(2, 32), 9],
186
187
    // don't go above this, is signed int territory, PHP complains
188
    // nodejs?
189
    [0x7fffffffffffffff, 9]
190
];
191
192
var scriptDataLenFixtures =  [
193
    [0, 1],
194
    [1, 1],
195
    [74, 1],
196
    [75, 2],
197
    [76, 2],
198
    [254, 2],
199
    [255, 2],
200
    [256, 3],
201
    [65534, 3],
202
    [65535, 3],
203
    [65536, 5]
204
];
205
206
var p2pkStackFixtures = (function() {
207
    var u = '5KW8Ymmu8gWManGggZZQJeX7U3pn5HtcqqsVrNUbc1SUmVPZbwp';
208
    var c = 'L1Tr4rPUi81XN1Dp48iuva5U9sWxU1eipgiAu8BhnB3xnSfGV5rd';
209
210
    var fixtures = [];
211
212
    fixtures.push([p2pkMakeScript(u, bitcoin.networks.bitcoin)]);
213
    fixtures.push([p2pkMakeScript(c, bitcoin.networks.bitcoin)]);
214
215
    return fixtures;
216
})();
217
218
// test fixtures of every possible representation of multisig
219
var p2pkFormFixtures = (function() {
220
    return []
221
        .concat(p2pkMakeFormFixtures('5KW8Ymmu8gWManGggZZQJeX7U3pn5HtcqqsVrNUbc1SUmVPZbwp', bitcoin.networks.bitcoin))
222
        .concat(p2pkMakeFormFixtures('L1Tr4rPUi81XN1Dp48iuva5U9sWxU1eipgiAu8BhnB3xnSfGV5rd', bitcoin.networks.bitcoin));
223
})();
224
225
var p2pkhStackFixtures = (function() {
226
    var u = '5KW8Ymmu8gWManGggZZQJeX7U3pn5HtcqqsVrNUbc1SUmVPZbwp';
227
    var c = 'L1Tr4rPUi81XN1Dp48iuva5U9sWxU1eipgiAu8BhnB3xnSfGV5rd';
228
229
    var fixtures = [];
230
    fixtures.push([p2pkhMakeScript(u, bitcoin.networks.bitcoin)]);
231
    fixtures.push([p2pkhMakeScript(c, bitcoin.networks.bitcoin)]);
232
233
    return fixtures;
234
})();
235
236
// test fixtures of every possible representation of multisig
237
var p2pkhFormFixtures = (function() {
238
239
    return []
240
        .concat(p2pkhFormFixture('L1Tr4rPUi81XN1Dp48iuva5U9sWxU1eipgiAu8BhnB3xnSfGV5rd', bitcoin.networks.bitcoin))
241
        .concat(p2pkhFormFixture('5KW8Ymmu8gWManGggZZQJeX7U3pn5HtcqqsVrNUbc1SUmVPZbwp', bitcoin.networks.bitcoin))
242
    ;
243
})();
244
245
var multisigStackFixtures = (function() {
246
    var u = ['5KW8Ymmu8gWManGggZZQJeX7U3pn5HtcqqsVrNUbc1SUmVPZbwp',
247
        '5KCV94YBsrJWTdk6cQWJxEd25sH8h1cGTpJnCN6kLMLe4c3QZVr',
248
        '5JUxGateMWVBsBQkAwSRQLxyaQXhsch4EStfC62cqdEf2zUheVT'
249
    ];
250
    var c = ['L1Tr4rPUi81XN1Dp48iuva5U9sWxU1eipgiAu8BhnB3xnSfGV5rd',
251
        'KwUZpCvpAkUe1SZj3k3P2acta1V1jY8Dpuj71bEAukEKVrg8NEym',
252
        'Kz2Lm2hzjPWhv3WW9Na5HUKi4qBxoTfv8fNYAU6KV6TZYVGdK5HW'
253
    ];
254
    var uncompressed = u.map(function(wif) {
255
        return bitcoin.ECPair.fromWIF(wif, bitcoin.networks.bitcoin);
256
    });
257
    var compressed = c.map(function(wif) {
258
        return bitcoin.ECPair.fromWIF(wif, bitcoin.networks.bitcoin);
259
    });
260
261
    var fixtures = [];
262
    for (var i = 0; i < 3; i++) {
263
        var keys = [];
264
        var j;
265
        for (j = 0; j < i; j++) {
266
            keys.push(uncompressed[j].getPublicKeyBuffer());
267
        }
268
        for (j = i; j < 3; j++) {
269
            keys.push(compressed[j].getPublicKeyBuffer());
270
        }
271
272
        fixtures.push([bitcoin.script.multisig.output.encode(2, keys)]);
273
    }
274
275
    return fixtures;
276
})();
277
278
// test fixtures of every possible representation of multisig
279
var multisigFormFixtures = (function() {
280
    var multisig = multisigMakeScript(2, ['L1Tr4rPUi81XN1Dp48iuva5U9sWxU1eipgiAu8BhnB3xnSfGV5rd',
281
        'KwUZpCvpAkUe1SZj3k3P2acta1V1jY8Dpuj71bEAukEKVrg8NEym',
282
        'Kz2Lm2hzjPWhv3WW9Na5HUKi4qBxoTfv8fNYAU6KV6TZYVGdK5HW'
283
    ], bitcoin.networks.bitcoin);
284
285
    var msDetail = multisigScriptSizes(2, multisig);
286
287
    return []
288
        .concat(makeFormFixtures(multisig, msDetail));
289
})();
290
291
// test fixtures of every possible representation of multisig
292
var multisigUtxoFixtures = (function() {
293
    var data = [
294
        [
295
            2,
296
            [
297
                'L1Tr4rPUi81XN1Dp48iuva5U9sWxU1eipgiAu8BhnB3xnSfGV5rd',
298
                'KwUZpCvpAkUe1SZj3k3P2acta1V1jY8Dpuj71bEAukEKVrg8NEym',
299
                'Kz2Lm2hzjPWhv3WW9Na5HUKi4qBxoTfv8fNYAU6KV6TZYVGdK5HW'
300
            ],
301
            bitcoin.networks.bitcoin
302
        ],
303
        [
304
            3,
305
            [
306
                'L1Tr4rPUi81XN1Dp48iuva5U9sWxU1eipgiAu8BhnB3xnSfGV5rd',
307
                'KwUZpCvpAkUe1SZj3k3P2acta1V1jY8Dpuj71bEAukEKVrg8NEym',
308
                'Kz2Lm2hzjPWhv3WW9Na5HUKi4qBxoTfv8fNYAU6KV6TZYVGdK5HW'
309
            ],
310
            bitcoin.networks.bitcoin
311
        ],
312
        [
313
            1,
314
            [
315
                'L1Tr4rPUi81XN1Dp48iuva5U9sWxU1eipgiAu8BhnB3xnSfGV5rd'
316
            ],
317
            bitcoin.networks.bitcoin
318
        ]
319
    ];
320
321
    var fixtures = [];
322
    data.map(function(fixture) {
323
        var script = multisigMakeScript(fixture[0], fixture[1], fixture[2]);
324
        var msDetail = multisigScriptSizes(fixture[0], script);
325
        makeUtxoFixtures(script, msDetail).map(function(fixture) {
326
            fixtures.push(fixture);
327
        });
328
    });
329
330
    return fixtures;
331
})();
332
333
// test fixtures of every possible representation of multisig
334
var p2pkUtxoFixtures = (function() {
335
    var data = [
336
        [
337
            'L1Tr4rPUi81XN1Dp48iuva5U9sWxU1eipgiAu8BhnB3xnSfGV5rd',
338
            bitcoin.networks.bitcoin
339
        ],
340
        [
341
            'KwUZpCvpAkUe1SZj3k3P2acta1V1jY8Dpuj71bEAukEKVrg8NEym',
342
            bitcoin.networks.bitcoin
343
        ],
344
        [
345
            'Kz2Lm2hzjPWhv3WW9Na5HUKi4qBxoTfv8fNYAU6KV6TZYVGdK5HW',
346
            bitcoin.networks.bitcoin
347
        ]
348
    ];
349
350
    var fixtures = [];
351
    data.map(function(fixture) {
352
        var script = p2pkMakeScript(fixture[0], fixture[1]);
353
        var msDetail = p2pkScriptSizes(script);
354
        makeUtxoFixtures(script, msDetail).map(function(fixture) {
355
            fixtures.push(fixture);
356
        });
357
    });
358
359
    return fixtures;
360
})();
361
362
// test fixtures of every possible representation of multisig
363
var p2pkhUtxoFixtures = (function() {
364
    var data = [
365
        [
366
            'L1Tr4rPUi81XN1Dp48iuva5U9sWxU1eipgiAu8BhnB3xnSfGV5rd',
367
            bitcoin.networks.bitcoin
368
        ]
369
    ];
370
371
    var fixtures = [];
372
    data.map(function(fixture) {
373
        var script = p2pkhMakeScript(fixture[0], fixture[1]);
374
        var compressed = bitcoin.ECPair.fromWIF(fixture[0], fixture[1]).compressed;
375
        var msDetail = p2pkhScriptSizes(script, compressed);
376
        makeUtxoFixtures(script, msDetail, [compressed]).map(function(fixture) {
377
            fixtures.push(fixture);
378
        });
379
    });
380
381
    return fixtures;
382
})();
383
384
describe('SizeEstimation.getLengthForVarInt', function() {
385
    varIntFixtures.map(function(fixture) {
386
        var inputLen = fixture[0];
387
        var expectSize = fixture[1];
388
        it('works for `' + inputLen + '` (equals ' + expectSize + ')', function(cb) {
389
            var result = SizeEstimation.getLengthForVarInt(inputLen);
390
            assert.equal(expectSize, result);
391
            cb();
392
        });
393
    });
394
395
    it('throws when too large an input is provided', function(cb) {
396
        var err;
397
        try {
398
            SizeEstimation.getLengthForVarInt(0xffffffffffffffff + 1);
399
        } catch (e) {
400
            err = e;
401
        }
402
403
        assert.ok(typeof err === "object");
0 ignored issues
show
Bug introduced by
The variable err seems to not be initialized for all possible execution paths.
Loading history...
404
        assert.equal(err.message, "Size of varint too large");
405
        cb();
406
    });
407
});
408
409
describe('SizeEstimation.getLengthForScriptPush', function() {
410
    scriptDataLenFixtures.map(function(fixture) {
411
        var inputLen = fixture[0];
412
        var expectSize = fixture[1];
413
        it(' works for ' + inputLen + '` (equals ' + expectSize + ')', function(cb) {
414
            var result = SizeEstimation.getLengthForScriptPush(inputLen);
415
            assert.equal(expectSize, result);
416
            cb();
417
        });
418
    });
419
420
    it('throws when too large an input is provided', function(cb) {
421
        var err;
422
        try {
423
            SizeEstimation.getLengthForScriptPush(0xffffffff + 1);
424
        } catch (e) {
425
            err = e;
426
        }
427
428
        assert.ok(typeof err === "object");
0 ignored issues
show
Bug introduced by
The variable err seems to not be initialized for all possible execution paths.
Loading history...
429
        assert.equal(err.message, "Size of pushdata too large");
430
        cb();
431
    });
432
});
433
434
describe('estimateP2PKStackSize', function() {
435
    p2pkStackFixtures.map(function(fixture) {
436
        it("works for p2pk scripts with the keys", function(cb) {
437
            var script = fixture[0];
438
            assert.ok(bitcoin.script.pubKey.output.check(script));
439
            var decoded = bitcoin.script.pubKey.output.decode(script);
440
441
            var estimation = SizeEstimation.estimateP2PKStackSize(decoded);
442
            assert.equal("object", typeof estimation);
443
            assert.equal(2, estimation.length);
444
445
            var scriptSize = estimation[1];
446
            assert.equal(script.length, scriptSize);
447
448
            var stackSizes = estimation[0];
449
            assert.equal(1, stackSizes.length);
450
            assert.equal(SizeEstimation.SIZE_DER_SIGNATURE, stackSizes[0]);
451
            cb();
452
        });
453
    });
454
455
    p2pkFormFixtures.map(function(fixture) {
456
        it("deals with different representations", function(cb) {
457
            var script = fixture[0];
458
            var isWit = fixture[1];
459
            var rs = fixture[2];
460
            var ws = fixture[3];
461
            var expectSig = fixture[4];
462
            var expectWit = fixture[5];
463
464
            assert.ok(bitcoin.script.pubKey.output.check(script));
465
            var decoded = bitcoin.script.pubKey.output.decode(script);
466
            var stackEst = SizeEstimation.estimateP2PKStackSize(decoded);
467
            var stackSizes = stackEst[0];
468
469
            var est = SizeEstimation.estimateStackSignatureSize(stackSizes, isWit, rs, ws);
470
            assert.equal("object", typeof est);
471
            assert.equal(2, est.length);
472
473
            var foundSigSize = est[0];
474
            var foundWitSize = est[1];
475
476
            assert.equal(foundSigSize, expectSig);
477
            assert.equal(foundWitSize, expectWit);
478
            cb();
479
        });
480
    });
481
});
482
483
describe('estimateP2PKHStackSize', function() {
484
    p2pkhStackFixtures.map(function(fixture) {
485
        it("works for p2pkh scripts with the keys", function(cb) {
486
            var script = fixture[0];
487
            assert.ok(bitcoin.script.pubKeyHash.output.check(script));
488
            var decoded = bitcoin.script.pubKeyHash.output.decode(script);
489
490
            var estimation = SizeEstimation.estimateP2PKHStackSize(decoded);
491
            assert.equal("object", typeof estimation);
492
            assert.equal(2, estimation.length);
493
494
            var scriptSize = estimation[1];
495
            assert.equal(scriptSize, script.length);
496
497
            var stackSizes = estimation[0];
498
            assert.equal(2, stackSizes.length);
499
500
            assert.equal(stackSizes[0], SizeEstimation.SIZE_DER_SIGNATURE);
501
            assert.equal(stackSizes[1], 33);
502
            cb();
503
        });
504
    });
505
506
    p2pkhFormFixtures.map(function(fixture) {
507
        it("deals with different representations", function(cb) {
508
            var script = fixture[0];
509
            var isWit = fixture[1];
510
            var rs = fixture[2];
511
            var ws = fixture[3];
512
            var expectSig = fixture[4];
513
            var expectWit = fixture[5];
514
            var compressed = fixture[6];
515
516
            assert.ok(bitcoin.script.pubKeyHash.output.check(script));
517
518
            var stackEst = SizeEstimation.estimateP2PKHStackSize(compressed);
519
            var stackSizes = stackEst[0];
520
521
            var est = SizeEstimation.estimateStackSignatureSize(stackSizes, isWit, rs, ws);
522
            assert.equal("object", typeof est);
523
            assert.equal(2, est.length);
524
525
            var foundSigSize = est[0];
526
            var foundWitSize = est[1];
527
528
            assert.equal(foundSigSize, expectSig);
529
            assert.equal(foundWitSize, expectWit);
530
            cb();
531
        });
532
    });
533
});
534
535
describe("estimateMultisigStackSize", function() {
536
    multisigStackFixtures.map(function(fixture) {
537
        it("works for multisig scripts with the keys", function(cb) {
538
            var script = fixture[0];
539
            assert.ok(bitcoin.script.multisig.output.check(script));
540
            var decoded = bitcoin.script.multisig.output.decode(script);
541
            var estimation = SizeEstimation.estimateMultisigStackSize(decoded.m, decoded.pubKeys);
542
543
            assert.equal("object", typeof estimation);
544
            assert.equal(2, estimation.length);
545
546
            var scriptSize = estimation[1];
547
            assert.equal(script.length, scriptSize);
548
549
            var stackSizes = estimation[0];
550
            assert.equal(1 + decoded.m, stackSizes.length);
551
            assert.equal(0, stackSizes[0]);
552
            for (var i = 0; i < decoded.m; i++) {
553
                assert.equal(SizeEstimation.SIZE_DER_SIGNATURE, stackSizes[1 + i]);
554
            }
555
            cb();
556
        });
557
    });
558
559
    multisigFormFixtures.map(function(fixture) {
560
        it("deals with different representations", function(cb) {
561
            var script = fixture[0];
562
            var isWit = fixture[1];
563
            var rs = fixture[2];
564
            var ws = fixture[3];
565
            var expectSig = fixture[4];
566
            var expectWit = fixture[5];
567
568
            assert.ok(bitcoin.script.multisig.output.check(script));
569
            var multisig = bitcoin.script.multisig.output.decode(script);
570
571
            var stackEst = SizeEstimation.estimateMultisigStackSize(multisig.m, multisig.pubKeys);
572
            var stackSizes = stackEst[0];
573
574
            var est = SizeEstimation.estimateStackSignatureSize(stackSizes, isWit, rs, ws);
575
            assert.equal("object", typeof est);
576
            assert.equal(2, est.length);
577
578
            var foundSigSize = est[0];
579
            var foundWitSize = est[1];
580
581
            assert.equal(foundSigSize, expectSig);
582
            assert.equal(foundWitSize, expectWit);
583
            cb();
584
        });
585
    });
586
587
});
588
589
describe("SizeEstimation.estimateInputFromScripts", function() {
590
    it('throws on invalid script type', function(cb) {
591
        var err;
592
        try {
593
            SizeEstimation.estimateInputFromScripts(Buffer.from('', 'hex'), null, null);
0 ignored issues
show
Bug introduced by
The variable Buffer seems to be never declared. If this is a global, consider adding a /** global: Buffer */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
594
        } catch (e) {
595
            err = e;
596
        }
597
598
        assert.ok(typeof err === "object");
0 ignored issues
show
Bug introduced by
The variable err seems to not be initialized for all possible execution paths.
Loading history...
599
        assert.equal(err.message, "Unsupported script type");
600
        cb();
601
    });
602
});
603
describe("SizeEstimation.estimateOutputs", function() {
604
    [0, 1, 5, 9].map(function(size) {
605
        it("estimates single output, for script size " + size, function(cb) {
606
            var script = '';
607
            for (var i = 0; i < size; i++) {
608
                script = script + '6a';
609
            }
610
            var outputsSize = SizeEstimation.calculateOutputsSize([{
611
                value: 1234,
612
                script: Buffer.from(script, 'hex')
0 ignored issues
show
Bug introduced by
The variable Buffer seems to be never declared. If this is a global, consider adding a /** global: Buffer */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
613
            }]);
614
            assert.equal(outputsSize, 8 + 1 + size);
615
            cb();
616
        });
617
    });
618
});
619
620
describe("SizeEstimation.estimateTxWeight", function() {
621
    var wif = "5KW8Ymmu8gWManGggZZQJeX7U3pn5HtcqqsVrNUbc1SUmVPZbwp";
622
    var key = bitcoin.ECPair.fromWIF(wif, bitcoin.networks.bitcoin);
623
    key.compressed = true;
624
625
    var hash160 = bitcoin.crypto.hash160(key.getPublicKeyBuffer());
626
    var p2wpkh = bitcoin.script.witnessPubKeyHash.output.encode(hash160);
627
    var p2pkh = bitcoin.script.pubKeyHash.output.encode(hash160);
628
629
    it("estimates p2wpkh weight", function(cb) {
630
        var utxos = [
631
            {
632
                txid: "abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234",
633
                vout: 0,
634
                scriptpubkey_hex: p2wpkh
635
            }
636
        ];
637
638
        var txb = new bitcoin.TransactionBuilder();
639
        utxos.map(function(utxo) {
640
            txb.addInput(utxo.txid, utxo.vout, bitcoin.Transaction.DEFAULT_SEQUENCE, p2wpkh);
641
        });
642
643
        txb.addOutput(p2wpkh, 1234);
644
        txb.sign(0, key, null, null, 0);
645
        var tx = txb.build();
646
647
        var weight = SizeEstimation.estimateTxWeight(tx, utxos);
648
        var vsize = SizeEstimation.estimateTxVsize(tx, utxos);
649
650
        assert.equal(vsize, 110);
651
        assert.equal(weight, 438);
652
        assert.equal(vsize, Math.ceil(weight / 4));
653
        cb();
654
    });
655
656
    it("estimates p2wpkh weight 2", function(cb) {
657
        var utxos = [
658
            {
659
                txid: "abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234",
660
                vout: 0,
661
                scriptpubkey_hex: p2wpkh
662
            },
663
            {
664
                txid: "abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd123e",
665
                vout: 0,
666
                scriptpubkey_hex: p2wpkh
667
            },
668
            {
669
                txid: "abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd123f",
670
                vout: 0,
671
                scriptpubkey_hex: p2wpkh
672
            }
673
        ];
674
675
        var txb = new bitcoin.TransactionBuilder();
676
        utxos.map(function(utxo) {
677
            txb.addInput(utxo.txid, utxo.vout, bitcoin.Transaction.DEFAULT_SEQUENCE, p2wpkh);
678
        });
679
680
        txb.addOutput(p2wpkh, 1234);
681
        txb.sign(0, key, null, null, 0);
682
        txb.sign(1, key, null, null, 0);
683
        txb.sign(2, key, null, null, 0);
684
        var tx = txb.build();
685
686
        var weight = SizeEstimation.estimateTxWeight(tx, utxos);
687
        var vsize = SizeEstimation.estimateTxVsize(tx, utxos);
688
689
        // NOTE; the REAL weight is 980, we overestimate by 1 byte because the signature is 1 byte shorter for the first 2 inputs
690
        assert.equal(vsize, 246);
691
        assert.equal(weight, 982);
692
        assert.equal(vsize, Math.ceil(weight / 4));
693
        cb();
694
    });
695
696
    it("weight for non-witness is 4x size", function(cb) {
697
        var utxos = [
698
            {
699
                txid: "abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234",
700
                vout: 0,
701
                scriptpubkey_hex: p2pkh
702
            },
703
            {
704
                txid: "abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd123e",
705
                vout: 0,
706
                scriptpubkey_hex: p2pkh
707
            },
708
            {
709
                txid: "abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd123f",
710
                vout: 0,
711
                scriptpubkey_hex: p2pkh
712
            }
713
        ];
714
715
        var txb = new bitcoin.TransactionBuilder();
716
        utxos.map(function(utxo) {
717
            txb.addInput(utxo.txid, utxo.vout);
718
        });
719
720
        txb.addOutput(p2wpkh, 1234);
721
        txb.addOutput(p2wpkh, 1234);
722
        txb.addOutput(p2wpkh, 1234);
723
        txb.sign(0, key);
724
        txb.sign(1, key);
725
        txb.sign(2, key);
726
        var tx = txb.build();
727
728
        var os = SizeEstimation.calculateOutputsSize(tx.outs);
729
        var bs = 4 + 1 + SizeEstimation.estimateInputsSize(utxos, false) + 1 + os + 4;
730
731
        var weight = SizeEstimation.estimateTxWeight(tx, utxos);
732
        // NOTE; the REAL weight is 2180, we overestimate by 1 byte because the signature is 1 byte shorter for the first 2 inputs
733
        assert.equal(weight, 2188);
734
        assert.equal(weight, bs * 4);
735
736
        var vsize = SizeEstimation.estimateTxVsize(tx, utxos);
737
        assert.equal(Math.ceil(weight / 4), vsize);
738
        cb();
739
    });
740
});
741
742
describe("SizeEstimation.estimateInputsSize", function() {
743
    var wif = "5KW8Ymmu8gWManGggZZQJeX7U3pn5HtcqqsVrNUbc1SUmVPZbwp";
744
    var key = bitcoin.ECPair.fromWIF(wif, bitcoin.networks.bitcoin);
745
746
    var hash160 = bitcoin.crypto.hash160(key.getPublicKeyBuffer());
747
    var p2wpkh = bitcoin.script.witnessPubKeyHash.output.encode(hash160);
748
749
    it("drops witness based on parameter", function(cb) {
750
        var withWitness = SizeEstimation.estimateInputsSize([{
751
            value: 1234,
752
            scriptpubkey_hex: p2wpkh
753
        }], true);
754
755
        var noWitness = SizeEstimation.estimateInputsSize([{
756
            value: 1234,
757
            scriptpubkey_hex: p2wpkh
758
        }], false);
759
760
        assert.equal(noWitness, 32 + 4 + 4 + 1);
761
        /*witness flags + witness vector*/
762
763
        var assumeSize = noWitness + 2 + (1 + 1 + SizeEstimation.SIZE_DER_SIGNATURE + 1 + 33);
764
765
        assert.ok(assumeSize === withWitness);
766
767
        cb();
768
    });
769
});
770
771
describe("SizeEstimation.estimateUtxo", function() {
772
    it("throws if P2SH and redeemScript not provided", function(cb) {
773
        var err;
774
        try {
775
            var hash160 = bitcoin.crypto.hash160(Buffer.from("42", "hex"));
0 ignored issues
show
Bug introduced by
The variable Buffer seems to be never declared. If this is a global, consider adding a /** global: Buffer */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
776
            var spk = bitcoin.script.scriptHash.output.encode(hash160);
777
            SizeEstimation.estimateUtxo({
778
                scriptpubkey_hex: spk,
779
                redeem_script: null
780
            });
781
        } catch (e) {
782
            err = e;
783
        }
784
785
        assert.ok(typeof err === "object");
0 ignored issues
show
Bug introduced by
The variable err seems to not be initialized for all possible execution paths.
Loading history...
786
        assert.equal(err.message, "Cant estimate, missing redeem script");
787
        cb();
788
    });
789
790
    it("throws if P2WSH and witnessScript not provided", function(cb) {
791
        var err;
792
        try {
793
            var hash160 = bitcoin.crypto.sha256(Buffer.from("42", "hex"));
0 ignored issues
show
Bug introduced by
The variable Buffer seems to be never declared. If this is a global, consider adding a /** global: Buffer */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
794
            var spk = bitcoin.script.witnessScriptHash.output.encode(hash160);
795
            SizeEstimation.estimateUtxo({
796
                scriptpubkey_hex: spk,
797
                witness_script: null
798
            });
799
        } catch (e) {
800
            err = e;
801
        }
802
803
        assert.ok(typeof err === "object");
0 ignored issues
show
Bug introduced by
The variable err seems to not be initialized for all possible execution paths.
Loading history...
804
        assert.equal(err.message, "Can't estimate, missing witness script");
805
        cb();
806
    });
807
808
    it("throws if unsupported script type", function(cb) {
809
        var err;
810
        try {
811
            var spk = Buffer.from('6a', 'hex');
0 ignored issues
show
Bug introduced by
The variable Buffer seems to be never declared. If this is a global, consider adding a /** global: Buffer */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
812
            SizeEstimation.estimateUtxo({
813
                scriptpubkey_hex: spk,
814
                witness_script: null
815
            });
816
        } catch (e) {
817
            err = e;
818
        }
819
820
        assert.ok(typeof err === "object");
0 ignored issues
show
Bug introduced by
The variable err seems to not be initialized for all possible execution paths.
Loading history...
821
        assert.equal(err.message, "Unsupported script type");
822
        cb();
823
    });
824
825
    []
826
        .concat(multisigUtxoFixtures)
827
        .concat(p2pkUtxoFixtures)
828
        .concat(p2pkhUtxoFixtures)
829
        .map(function(fixture) {
830
            it("deals with different representations", function(cb) {
831
                var utxo = fixture[0];
832
                var expectSig = fixture[1];
833
                var expectWit = fixture[2];
834
                var compressed = false;
835
                if (typeof fixture[3] === "boolean") {
836
                    compressed = fixture[3];
837
                }
838
839
                var estimate = SizeEstimation.estimateUtxo(utxo, compressed);
840
841
                assert.equal(estimate.scriptSig, expectSig);
842
                assert.equal(estimate.witness, expectWit);
843
                cb();
844
            });
845
        });
846
});
847
848
849
describe("estimateWitnessPubKeyHash", function() {
850
    it('should work', function(cb) {
851
        var utxo = { hash: '4141414141414141414141414141414141414141414141414141414141414141',
852
            idx: 2,
853
            scriptpubkey_hex: '00140102030401020304010203040102030401020304',
854
            value: 1,
855
            confirmations: 1,
856
            sign_mode: 'dont_sign',
857
            address: '2N245vnpchbFYWm5hZ6hqF2zC8QbVpoHeSU',
858
            path: null,
859
            redeem_script: null,
860
            witness_script: null,
861
            green: null };
862
863
        var estimation = SizeEstimation.estimateUtxo(utxo);
864
865
        assert.equal(1, estimation.scriptSig);
866
        assert.equal(108, estimation.witness);
867
868
        cb();
869
    });
870
});
871